home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / SBP2 / FWSBP2DiskDriver / FWSBP2DiskDriver.c next >
Encoding:
Text File  |  1999-05-17  |  70.2 KB  |  2,244 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWSBP2DiskDriver.c
  3.  
  4.     Contains:    Sample SBP-2 Hard Disk driver
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Clinton Bauder
  13.  
  14.         Other Contact:        Eric Anderson
  15.  
  16.         Technology:            FireWire
  17.  
  18.     Writers:
  19.  
  20.         (EA)    Eric Anderson (ewa)
  21.         (DCB)    Clinton Bauder
  22.  
  23.     Change History (most recent first):
  24.  
  25.       <FW42>      5/4/99    DCB        Clear the gpFWSBP2DriverData->loginObjBusy variable if we fail
  26.                                     find a drive when we go looking for it. This fixes the problem
  27.                                     where a drive doesn't re-mount after being dragged to the trash.
  28.       <FW41>     4/30/99    EA        Changed to protect the LUN reset object from being used when it
  29.                                     is already in use.
  30.       <FW40>     4/29/99    DCB        Fixed a problem with the lookfordrive function which was
  31.                                     re-using the login command object when it shouldn't be. Now it
  32.                                     uses the loginObjBusy variable to protect both the login object
  33.                                     and the CSR read object from premature re-use. Also added code
  34.                                     to not retry requests if we get ORB status while in the midst of
  35.                                     logging in or reconnecting. Sometimes we get called with
  36.                                     notification twice for the same ORB after a reset. This prevents
  37.                                     us from trying to use the Management Agent to reset the LUN or
  38.                                     do other error recovery until we're sure we're logged in again.
  39.       <FW39>     4/29/99    EA        Changed to restore BUSY_TIMEOUT after each login or reconnect.
  40.       <FW38>     4/24/99    EA        Changed FWSetRetryResponseOnAckDataErr to FWSetFWDeviceFlags.
  41.                                     Also changed to set kFWDeviceDoNotEjectCardBus flag while we
  42.                                     have a volume (possibly) mounted.
  43.       <FW37>     4/22/99    DCB        Add a missing break to the main dispatch loop. Mostly for
  44.                                     neatness. Doesn't change the generated code.
  45.       <FW36>     4/17/99    DCB        Don't unilaterally return statusErr from the status routine.
  46.                                     Return the real error if any. Get rid of non-functional ROM
  47.                                     flashing code. Call IOCommandIsComplete if we get an error from
  48.                                     readwriteblocks so we don't hang. Fixed a "flashing dialog"
  49.                                     problem for wall powered devices caused by improper handling of
  50.                                     login failed notifications.
  51.       <FW35>     3/31/99    EA        Added call to FWSetRetryResponseOnAckDataErr for better
  52.                                     performance.
  53.       <FW34>     3/27/99    EA        Changed descriptor back to sbp609e,104d8 (from sbp0,0).
  54.       <FW33>     3/27/99    EA        Changed to use aligned double-buffer for any request of 8K or
  55.                                     less.
  56.       <FW32>     3/15/99    DCB        Mask the incoming buffer with 0x0000000F instead of 0x00000007
  57.                                     when deciding to double buffer as some devices have trouble with
  58.                                     the smaller alignment restriction.
  59.       <FW31>      3/8/99    DCB        Lengthen the timeout for TURs to 5 seconds. Some devices don't
  60.                                     like a LUNReset command while a TUR is still active.
  61.       <FW30>      3/8/99    DCB        Slight improvement in the way we handle ReadCapacity commands.
  62.                                     Some devices after a crash can get into a state where the return
  63.                                     good status for this command but don't actually send us any
  64.                                     data. Now if we don't get a valid capacity we return an error up
  65.                                     the chain and don't load the driver. I'm investigating ways to
  66.                                     reset the drive to fix the problem for real but this is better
  67.                                     than creating a bogus drive queue element and risking erasing
  68.                                     the volume.
  69.       <FW29>      3/8/99    DCB        And one more change. Changed the TheDFMDescriptor ranges for
  70.                                     VendorID and SoftwareRev to "don't care" from "match
  71.                                     everything". This makes it easier for "real" drivers with more
  72.                                     specific DFMDescriptors to override this driver.
  73.       <FW28>      3/8/99    DCB        Lots of cleanup and some real improvements too. Now if
  74.                                     needLUNReset is set true in the header file we use the
  75.                                     FWSBP2Manage function to reset the LUN before resetting the
  76.                                     fetch agent. Allows us to recover from bad packets on devices
  77.                                     that don't always respond to a fetch agent reset (you know who
  78.                                     you are...). Also cleaned up the state variables for keeping
  79.                                     track of logins. Now logout on eject control call to spin down
  80.                                     the disk. Also make sure we're done logging out before
  81.                                     de-allocating the login ORB if our initial login failed.
  82.       <FW27>      3/4/99    DCB        Two things: Fixed a performance issue with double buffering for
  83.                                     reads. We were blockmoving the size of the whole buffer for each
  84.                                     chunk, not the chunk size. Second add support for verifying
  85.                                     writes. Sorry about the clutter but it is pretty useful for
  86.                                     tracking down data corruption problems.
  87.       <FW26>      3/2/99    DCB        Add support for a bunch of DriverGestalt calls. Also now if we
  88.                                     get login failed notification we try to login again on the
  89.                                     assumption that we were unplugged or reset during a login.
  90.       <FW25>     2/15/99    DCB        Add better support for 2 macs-1 drive, that is do the right
  91.                                     thing if we fail a login.
  92.       <FW24>     2/15/99    DCB        Add support for Eric's notification changes. Basically now we
  93.                                     assume ORBs are canceled immediately following a reset. Also
  94.                                     don't bother paying attention to resets if we are waiting for a
  95.                                     re-plug. Let FSL do that for us.
  96.       <FW23>     2/12/99    EA        Changed max payload size to 256 for now.
  97.       <FW22>      2/8/99    DCB        Make the DFMDescriptor and DriverDescriptor more correct (and
  98.                                     specific).
  99.       <FW21>     1/25/99    DCB        Misc. Cleanup of the re-plug code. Handle loginFailed responses
  100.                                     better. Try to prevent re-entrant us of resources related to
  101.                                     logging in after the reconnect timeout fails.
  102.       <FW20>     1/21/99    DCB        Clear the gotEject flag on a login so we know the drive is
  103.                                     around and don't inadvertently return errors.
  104.       <FW19>     1/21/99    DCB        Cleaned up the hot-unplugging code to get rid of the unnecessary
  105.                                     DeviceNotify stuff and use instead the brand new
  106.                                     FWWaitForDeviceRePlug() API I just invented. Now we get a DSAT
  107.                                     warning if the drive goes away unexpectedly. If the user cancels
  108.                                     this with Command-. we start returning ioErr until the drive
  109.                                     returns.
  110.       <FW18>     1/19/99    EA        Fixed FlashSymbiosROM to set the generation value so that the
  111.                                     flag kFWAsynchFailOnBusReset will work as intended.
  112.       <FW17>     1/19/99    DCB        Clean up some comments and the Finalize routine (still never
  113.                                     called but it should at least show what should be done).
  114.       <FW16>     1/19/99    DCB        Did a couple of things. First we now nearly always recover from
  115.                                     a hot unplug followed by a re-plug. Occasionally we don't get
  116.                                     ORB notification for an outstanding ORB if the re-plug happens
  117.                                     before the reconnect fails. Unplugging and replugging again
  118.                                     fixes this. The bug appears to be in FSL. I also added a boolean
  119.                                     in the eject code which we use to keep track of whether the disk
  120.                                     has been unmounted. If so we post a diskEvt every time we login.
  121.                                     This way the drive re-appears when re-plugged after being
  122.                                     unmounted and unplugged. User dialogs asking for a disk to be
  123.                                     inserted when hot unplugged while a volume is mounted are not
  124.                                     implemented yet. Stay tuned.
  125.       <FW15>     1/15/99    EA        Changed to set the BUSY_TIMEOUT register in the drive so that it
  126.                                     will retry busy packets.  This works (helps?) on the LSI Native
  127.                                     Bridge.  Removed kFWCommandSyncFlag from asynch command flags
  128.                                     (it is a plain command flag, and those are different).  Gave
  129.                                     FlashSymbiosROM its own command object but did not test this as
  130.                                     I have no card to flash.
  131.       <FW14>     1/15/99    DCB        Don't return an error from eject. This allows us to unmount the
  132.                                     drive before unplugging it without getting an annoying error
  133.                                     from the finder.
  134.       <FW13>     1/15/99    DCB        Nearly almost have hot-unplugging and re-plugging working. See
  135.                                     my comment block in the device notification section for details
  136.                                     on why it doesn't _quite_ work yet.
  137.       <FW12>      1/3/99    EA        Changed to set kSBP2CommandNormalORB flag for normal ORBs.
  138.       <FW11>    12/31/98    EA        Changed to pre-allocate 12288 bytes of storage for each normal
  139.                                     command object, as per the latest SBP-2 API document.
  140.       <FW10>    12/29/98    DCB        Double buffer requests if the buffer passed in from the OS is
  141.                                     not aligned to a cache line. SBP is unclear on whether this is
  142.                                     required but some devices clearly need it.
  143.        <FW9>    12/23/98    DCB        Don't do ReqSense anymore as some drives don't like this. Back
  144.                                     to straight retries for error checking. Also fixed up the
  145.                                     Symbios ROM flash code.
  146.        <FW8>    12/19/98    DCB        Minor cleanup of the sample Symbios ROM and ATA mode code at the
  147.                                     end of this file.
  148.        <FW7>    12/18/98    DCB        Make sure we wait for login before trying to use the fetch
  149.                                     agent.
  150.        <FW6>    12/18/98    DCB        Fix some things up for native bridge support. Make request sense
  151.                                     calls now when fetch agent goes dead. Much better threading and
  152.                                     error recovery when we write to the fetch agent's reset
  153.                                     register.
  154.        <FW5>     12/7/98    EA        Removed brand name from comment.
  155.        <FW4>     12/1/98    EA        Changed to set maximum payload size to 512 in login command
  156.                                     object (default is 4, but it wasn't previously enforced).
  157.        <FW3>    11/20/98    DCB        Use Eric's new API to decide which ORB we just got notification
  158.                                     for. Also clean up some comments.
  159.        <FW2>    11/17/98    DCB        Misc Cleanup.
  160.        <FW1>    11/17/98    DCB        first checked in
  161.        <FW3>    10/28/98    DCB        Using new defs for matching SBP drivers. This allows us to be
  162.                                     much more specific in our decision as to which driver belongs to
  163.                                     which device.
  164.        <FW2>     9/20/98    EA        Filled in header comments.
  165.        <FW1>     9/20/98    EA        first checked in
  166. */
  167.  
  168.  
  169. #include <Types.h>
  170. #include <Files.h>
  171. #include <Errors.h>
  172. #include <Disks.h>
  173. #include <DriverGestalt.h>
  174. #include <OSUtils.h>
  175. #include <Devices.h>
  176. #include <DriverServices.h>
  177. #include <LowMem.h>
  178. #include <FireWire.h>
  179. #include <FireWireSBP2.h>
  180. #include <SampleSBP2.h>
  181. #include <FWSBP2DiskDriver.h>
  182. /*zzz*/
  183. #include <TextUtils.h>
  184. #include <stdio.h>
  185. char    debugStr[256];
  186. /*zzz*/
  187.  
  188.  
  189. ////////////////////////////////////////////////////////////////////////////////
  190. //
  191. // Notes and Caveats
  192. //
  193. // This is an example of how to use SPB rather than an example of a complete
  194. // hard disk driver. It is, in fact, a long way from being a shipping product
  195. // and should be viewed as such.
  196. //
  197. // This driver uses the whole hard disk and doesn't understand partitions.
  198. //
  199. // Support for immediate calls is suspect at best.
  200. //
  201. // Error handling consists entirely of retries no matter what went wrong.
  202. //
  203. // DriverGestalt call support is a bit minimal (but better than what it was).
  204. //
  205. // The DFMDescriptor in this file is quite imprecise and will install this driver
  206. // on a wide variety of devices. 
  207. //
  208. // This driver makes no attempt to manage or handle bus power. It should use
  209. // the power APIs in FireWire 2.0 to ask if there is enough power to spin up
  210. // the drive before logging in (assuming the drive is bus powered).
  211. //
  212. // No attempt is made to provide exclusive access to one client save the normal
  213. // SBP2 login. Which mac gets a drive after it shows up on a local FireWire net
  214. // is strictly first come first serve. This is true even after a re-plug when one
  215. // of the Macs might have a volume mounted. In this case if another Mac gets the
  216. // login bad things will happen.
  217.  
  218. ////////////////////////////////////////////////////////////////////////////////
  219. //
  220. // Internal procedure prototypes.
  221. //
  222.  
  223. OSErr    DoDriverIO(
  224.     AddressSpaceID                addressSpaceID,
  225.     IOCommandID                    ioCommandID,
  226.     IOCommandContents            ioCommandContents,
  227.     IOCommandCode                ioCommandCode,
  228.     IOCommandKind                ioCommandKind);
  229.  
  230. static OSStatus    FWSBP2Initialize (
  231.     RegEntryIDPtr                pRegEntryID,
  232.     SInt16                        refNum);
  233.  
  234. static OSStatus    FWSBP2Terminate (void);
  235.  
  236. static OSStatus    SBP2Logout ( void );
  237.  
  238. static OSStatus SBP2DoReadWriteBlocks(
  239.     Boolean            isWrite,
  240.     UInt32             count,
  241.     UInt32             sector,
  242.     Ptr             buffer,
  243.     Boolean            immediate ) ;
  244.  
  245. static OSStatus FWSBP2Prime(
  246.     AddressSpaceID                addressSpaceID,
  247.     IOCommandID                    ioCommandID,
  248.     IOCommandContents            ioCommandContents,
  249.     IOCommandKind                ioCommandKind,
  250.     Boolean                        isWrite);
  251.  
  252. static OSStatus SBP2Control (
  253.     AddressSpaceID                addressSpaceID,
  254.     IOCommandID                    ioCommandID,
  255.     IOCommandContents            ioCommandContents,
  256.     IOCommandKind                ioCommandKind);
  257.  
  258. static OSStatus SBP2Status (
  259.     AddressSpaceID                addressSpaceID,
  260.     IOCommandID                    ioCommandID,
  261.     IOCommandContents            ioCommandContents,
  262.     IOCommandKind                ioCommandKind);
  263.  
  264. static OSStatus SBPLoginNotify(
  265.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  266.     UInt32                        *pCommandAcceptance);
  267.  
  268. static OSStatus SBPStatusNotify(
  269.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  270.     UInt32                        *pCommandAcceptance);
  271.  
  272. static OSStatus SBPUnsolicitedStatusNotify(
  273.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  274.     UInt32                        *pCommandAcceptance);
  275.     
  276. static OSStatus SBP2CalculateMediaSize( void );
  277.  
  278. void ResetFACompletionProc(
  279.     FWCommandObjectID            fwCommandObjectID,
  280.     OSStatus                    commandStatus,
  281.     UInt32                        completionProcData);
  282.     
  283. void BusyTimeoutCompletionProc(
  284.     FWCommandObjectID            fwCommandObjectID,
  285.     OSStatus                    commandStatus,
  286.     UInt32                        completionProcData);
  287.  
  288. void LoginCompletionProc(
  289.     FWCommandObjectID            fwCommandObjectID,
  290.     OSStatus                    commandStatus,
  291.     UInt32                        completionProcData);
  292.  
  293. void ManageCompletionProc(
  294.     FWCommandObjectID            fwCommandObjectID,
  295.     OSStatus                    commandStatus,
  296.     UInt32                        completionProcData);
  297.  
  298. void ReconnectReadCompletionProc(
  299.     FWCommandObjectID            fwCommandObjectID,
  300.     OSStatus                    commandStatus,
  301.     UInt32                        completionProcData);
  302.  
  303. void ReplugCompletionProc(
  304.     FWCommandObjectID            fwCommandObjectID,
  305.     OSStatus                    commandStatus,
  306.     UInt32                        completionProcData);
  307.  
  308. static OSStatus SBP2TUR( Boolean  );
  309.  
  310. static OSStatus SetBUSY_TIMEOUT (void);
  311.  
  312. static OSStatus    FWSBPResetNotify (
  313.     FWClientInterfaceParamsPtr    pFWClientInterfaceParams,
  314.     UInt32                        *pCommandAcceptance);
  315.  
  316. static void FWSBPLookForDrive( void );
  317.  
  318. ////////////////////////////////////////////////////////////////////////////////
  319. //
  320. // The driver descriptor.
  321. //
  322.  
  323. DriverDescription             TheDriverDescription =
  324. {
  325.     kTheDescriptionSignature,
  326.     kInitialDriverDescriptor,
  327.     {
  328.         "\psbp609e,104d8",        // Official Mass Storage values
  329.         1, 0, finalStage, 1,
  330.     },
  331.     {
  332.         kDriverIsUnderExpertControl |
  333.         kDriverIsOpenedUponLoad,
  334.         "\p.FWSBP2DiskDriver",
  335.     },
  336.  
  337.     1,
  338.     kServiceCategoryNdrvDriver,
  339.     kNdrvTypeIsBlockStorage,
  340.     1,0,0,0
  341. };
  342.  
  343. // Should match above. Probably needs to come from the same constants...
  344. const NumVersion gFWDiskVersion = {1, 0, finalStage, 0};
  345.  
  346. ////////////////////////////////////////////////////////////////////////////////
  347. //
  348. // A quick note on how this works:
  349. //
  350. // The SBP2Expert creates sub-nodes for each LUN 
  351. // ...:firewire:fw609e,10483
  352. // ...:firewire:fw609e,10483:sbpXXXXXX,YYYYYY
  353. // ...:firewire:fw609e,10483:sbpPPPPPP,QQQQQQ
  354. //
  355. // XXXXXX is the command_set_spec_ID of lun 0.  YYYYYY is the command_set of lun 0.
  356. // PPPPPP is the command_set_spec_ID if lun 1.  QQQQQQ is the command_set of lun 1.  etc.
  357. //
  358. // The name of the driver then should match the sub-node created by the expert. To further
  359. // narrow down the match the SBP2Expert creates a table with the VendorID, SoftwareRev,
  360. // FirmwareRev, LUN and device_type values from the CSR ROM. This table is contained  in
  361. // a property called "TheDFMTable". The format for this table is in FireWireSBP2.h.
  362. // A similar table is exported by the driver and is called TheDFMDescriptor. It is exactly
  363. // twice the size of TheDFMTable as it contains a range for each value exported by the expert.
  364. // Drivers which match the greatest number of values in the table are selected to match the
  365. // device. Fields with a negative range are marked as "don't care". 
  366. //
  367. // Note that "don't care" is different from matching everything. Matching everything means
  368. // the score for the driver will be incremented for that field while don't care means that
  369. // it won't be. Thus a driver with 3 matches and 1 don't care scores lower than a driver
  370. // with 4 matches - even if the matches are the 0 through 0xFFFFFFFF type.
  371. //
  372. // Drivers with identical scores will be ranked by version as with other native drivers.
  373.  
  374.  
  375. // This particular DFMDescriptor isn't very specific. A real driver will need to better
  376. // identify the device it works with.
  377.  
  378. SBPMatchData                        TheDFMDescriptor = 
  379. {
  380.     0x00000000, 0xFFFFFFFF,            // VendorID, don't care
  381.     0x00000000, 0xFFFFFFFF,            // SoftwareRev, don't care
  382.     0x00000000, 0xFFFFFFFF,            // FirmwareRev, don't care 
  383.     0x00000000, 0x00000000,            // LUN, match 0x00000000 
  384.     0x00000000, 0x00000000            // device_type, match 0x00000000 
  385.                                     // RBC is always type 0xe.
  386. };
  387.  
  388. ////////////////////////////////////////////////////////////////////////////////
  389. //
  390. // Our ICON.
  391. //
  392.  
  393. static UInt32 staticIconData[64] =
  394. {
  395.     0xFFFFFFFF, 0x80000001, 0x80000001, 0x80000001,
  396.     0x80000001, 0x80400201, 0x80A00501, 0x81400881,
  397.     0x82881041, 0x85142021, 0x82281041, 0x80500881,
  398.     0x80A3C501, 0x80442201, 0x80081001, 0x80081001,
  399.     0x80081001, 0x80081001, 0x80042001, 0x8003C001,
  400.     0x80000001, 0x8007E001, 0x80042001, 0x8007E001,
  401.     0x80000001, 0x8007E001, 0x80042001, 0x8007E001,
  402.     0x80000001, 0x80000001, 0x80000001, 0xFFFFFFFF,
  403.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  404.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  405.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  406.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  407.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  408.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  409.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  410.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
  411. };
  412.  
  413.  
  414. ////////////////////////////////////////////////////////////////////////////////
  415. //
  416. // Global driver data.
  417. //
  418.  
  419. FWSBP2DriverDataPtr                gpFWSBP2DriverData = nil;
  420.  
  421.  
  422. ////////////////////////////////////////////////////////////////////////////////
  423. //
  424. // DoDriverIO
  425. //
  426. //   Main entry point.
  427. //
  428.  
  429. OSErr    DoDriverIO(
  430.     AddressSpaceID                addressSpaceID,
  431.     IOCommandID                    ioCommandID,
  432.     IOCommandContents            ioCommandContents,
  433.     IOCommandCode                ioCommandCode,
  434.     IOCommandKind                ioCommandKind)
  435. {
  436.     OSErr                        err = noErr;
  437.  
  438.     switch (ioCommandCode)
  439.     {
  440.         case kInitializeCommand :
  441.             err = FWSBP2Initialize (&ioCommandContents.initialInfo->deviceEntry, ioCommandContents.initialInfo->refNum);
  442.             break;
  443.  
  444.         case kFinalizeCommand :
  445.             err = FWSBP2Terminate ();
  446.             break;
  447.  
  448.         case kOpenCommand :
  449.             break;
  450.  
  451.         case kReadCommand :
  452.             err = FWSBP2Prime (addressSpaceID,
  453.                         ioCommandID,
  454.                         ioCommandContents,
  455.                         ioCommandKind,
  456.                         false);
  457.             break;
  458.  
  459.         case kWriteCommand :
  460.             err = FWSBP2Prime (addressSpaceID,
  461.                         ioCommandID,
  462.                         ioCommandContents,
  463.                         ioCommandKind,
  464.                         true);
  465.             break;
  466.         case kCloseCommand :
  467.             err = SBP2Logout();
  468.             break;
  469.  
  470.         case kControlCommand :
  471.             err = SBP2Control(addressSpaceID,
  472.                         ioCommandID,
  473.                         ioCommandContents,
  474.                         ioCommandKind);
  475.             break;
  476.  
  477.         case kStatusCommand :
  478.             err = SBP2Status(addressSpaceID,
  479.                         ioCommandID,
  480.                         ioCommandContents,
  481.                         ioCommandKind);
  482.             break;
  483.  
  484.         default :
  485.             err = paramErr;
  486.     }
  487.  
  488.     return (err);
  489. }
  490.  
  491.  
  492. ////////////////////////////////////////////////////////////////////////////////
  493. //
  494. // FWSBP2Initialize
  495. //
  496. //   This routine initializes the FireWire SBP2 sample driver.  It
  497. // allocates a private data record and registers with the FireWire family.
  498. // It also prepares some command objects for use later on.
  499. //
  500.  
  501. static OSStatus SBPLoginNotify(
  502.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  503.     UInt32                        *pCommandAcceptance);
  504.  
  505. static OSStatus    FWSBP2Initialize(
  506.     RegEntryIDPtr                pRegEntryID,
  507.     SInt16                        refNum)
  508. {
  509.     FWSBP2DriverDataPtr            pFWSBP2DriverData = nil;
  510.     FWDriverID                    fwDriverID;
  511.     QHdrPtr                        pDrvQHdr;
  512.     DrvQElPtr                    pDrvQEl;
  513.     short                        driveNum;
  514.     UInt32                        orbNum;
  515.     UInt32                        keepTrying;
  516.     UInt32                        sizeTemp;
  517.     FWAddress                    addrTemp;
  518.     UInt32                        deviceFlags;
  519.     OSStatus                    status = noErr;
  520.  
  521.     // Allocate our driver data.
  522.     pFWSBP2DriverData =
  523.         (FWSBP2DriverDataPtr) PoolAllocateResident (sizeof (FWSBP2DriverData), true);
  524.     if (pFWSBP2DriverData == nil)
  525.     {
  526.         status = memFullErr;
  527.     }
  528.     else 
  529.         gpFWSBP2DriverData = pFWSBP2DriverData;
  530.  
  531.     // Register with the FireWire family.
  532.     if (status == noErr)
  533.     {
  534.         status = FWRegisterDriver (pRegEntryID,
  535.                                    &fwDriverID,
  536.                                    &(pFWSBP2DriverData->csrUnitID),
  537.                                    (UInt32) pFWSBP2DriverData);
  538.  
  539.         if (status == noErr)
  540.             pFWSBP2DriverData->fwDriverID = fwDriverID;
  541.             
  542.     }
  543.  
  544.     // Set the maximum packet payload size.
  545.     if (status == noErr)
  546.     {
  547.         status = FWSetMaxPayloadSize ((FWReferenceID) pFWSBP2DriverData->fwDriverID, kDiskDriverPayloadSize);
  548.     }
  549.  
  550.     // Tell FSL we want it to violate 1394-1995 by retrying when we underflow sending a response
  551.     // and get ack_data_err.
  552.     // Only do this if you know your device won't be confused if the Mac retries a response.
  553.     if (status == noErr)
  554.     {
  555.         // Note that we're running at task level, so if anyone tried to set flags
  556.         // between these two calls at non-task level we might undo their change.
  557.         
  558.         status = FWGetFWDeviceFlags ((FWReferenceID) pFWSBP2DriverData->fwDriverID, &deviceFlags);
  559.         
  560.         deviceFlags |= kFWDeviceRetryOnAckDataErr;
  561.         
  562.         if (status == noErr)
  563.             status = FWSetFWDeviceFlags ((FWReferenceID) pFWSBP2DriverData->fwDriverID, deviceFlags);
  564.     }
  565.  
  566.     // Allocate login command object.
  567.     if (status == noErr)
  568.     {
  569.         status = FWAllocateSBP2LoginCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  570.                                                    &pFWSBP2DriverData->loginCommandID);
  571.     }
  572.     
  573.     if (status != noErr) pFWSBP2DriverData->loginCommandID = 0;
  574.  
  575.     // Prepare login command object.
  576.     if (status == noErr)
  577.     {
  578.         status = FWSetSBP2LoginCommandFlags (pFWSBP2DriverData->loginCommandID,
  579.                                              kSBP2NotifyOnLoginComplete |
  580.                                              kSBP2NotifyOnLoginFailed |
  581.                                              kSBP2NotifyOnReconnecting |
  582.                                              kSBP2NotifyOnReconnectComplete |
  583.                                              kSBP2NotifyOnReconnectFailed |
  584.                                              kSBP2ExclusiveLogin );
  585.     }
  586.     
  587.     if (status == noErr)
  588.     {
  589.         status = FWSetSBP2LoginCommandLoginNotifyProc (pFWSBP2DriverData->loginCommandID,
  590.                                                        SBPLoginNotify,
  591.                                                        (UInt32) pFWSBP2DriverData);
  592.     }
  593.  
  594.     if (status == noErr)
  595.     {
  596.         status = FWSetSBP2LoginCommandStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  597.                                                         SBPStatusNotify,
  598.                                                         (UInt32) pFWSBP2DriverData);
  599.     }
  600.  
  601.     if (status == noErr)
  602.     {
  603.         status = FWSetSBP2LoginCommandUnsolicitedStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  604.                                                         SBPUnsolicitedStatusNotify,
  605.                                                         (UInt32) pFWSBP2DriverData);
  606.     }
  607.  
  608.     if (status == noErr)
  609.     {
  610.         status = FWSetFWCommandCompletionProc (pFWSBP2DriverData->loginCommandID,
  611.                                                         LoginCompletionProc);
  612.     }
  613.  
  614.     if (status == noErr)
  615.     {
  616.         status = FWSetSBP2LoginCommandMaxPayloadSize (pFWSBP2DriverData->loginCommandID, kDiskDriverPayloadSize );
  617.     }
  618.     
  619.     if( status == noErr)
  620.     {
  621.         status = FWAllocateSBP2ManagementCommandObject((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  622.                                                    &pFWSBP2DriverData->fwLUNReset_ID);
  623.     }
  624.     
  625.     if( status == noErr )
  626.     {
  627.         status = FWSetSBP2ManagementCommandFunction(pFWSBP2DriverData->fwLUNReset_ID, kSBP2LogicalUnitReset);
  628.     }
  629.     
  630.     if( status == noErr )
  631.     {
  632.         status = FWSetSBP2ManagementCommandCommandID( pFWSBP2DriverData->fwLUNReset_ID,
  633.                                                         pFWSBP2DriverData->loginCommandID);
  634.     }
  635.  
  636.     if (status == noErr)
  637.     {
  638.         status = FWSetFWCommandCompletionProc (pFWSBP2DriverData->fwLUNReset_ID,
  639.                                                         ManageCompletionProc);
  640.     }
  641.  
  642.     for( orbNum = 0; orbNum < kTotalORBs; orbNum++ ) {
  643.         // Allocate an ORB command object.
  644.         if (status == noErr)
  645.         {
  646.             status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  647.                                                         &pFWSBP2DriverData->orbID[orbNum]);
  648.             
  649.             // Memory is not automatically set aside for ORBs.  If we ever want to set up an
  650.             // ORB at non-task level, we will need to have memory allocated in advance.
  651.             
  652.             if (status == noErr)
  653.                 status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->orbID[orbNum], 12288);
  654.  
  655.             if (status == noErr)
  656.                 status = FWSetSBP2NormalCommandTimeout (pFWSBP2DriverData->orbID[orbNum], durationMillisecond * 1000);
  657.         }
  658.         
  659.         if (status != noErr) {
  660.             pFWSBP2DriverData->orbID[orbNum] = 0;
  661.             break;
  662.         }
  663.         
  664.     }
  665.  
  666.     pFWSBP2DriverData->currentORB = kAsyncORB;    // Switch between kAsyncORB and kAsyncORB + 1
  667.                                                 // Makes debugging easier since we can see
  668.                                                 // each new request go by in FireBug and also
  669.                                                 // in the receive buffer of the FWIM
  670.                                                 // Not really needed though.
  671.         
  672.     // Allocate an async command object for writing to the AGENT_RESET register.
  673.     // Need this in case the drive goes out to lunch. Writing this register doesn't always
  674.     // work, sometimes a bus reset or even power cycle is required. I don't know why yet
  675.     if (status == noErr)
  676.     {
  677.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwAGENT_RESET_ID);
  678.     }
  679.     
  680.     if (status == noErr)
  681.     {
  682.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwAGENT_RESET_ID,
  683.                                        pFWSBP2DriverData->fwDriverID,
  684.                                        0,
  685.                                        ResetFACompletionProc,
  686.                                        0);
  687.     }
  688.  
  689.     // Allocate an async command object for reading from the drive after it has gone
  690.     // away long enough for a reconnect to fail. We issue this read after any bus reset
  691.     // following a reconnect failed to see if our device came back.
  692.     if (status == noErr)
  693.     {
  694.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwReconnectID);
  695.     }
  696.     
  697.     if (status == noErr)
  698.     {
  699.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwReconnectID,
  700.                                        pFWSBP2DriverData->fwDriverID,
  701.                                        0,
  702.                                        ReconnectReadCompletionProc,
  703.                                        0);
  704.     }
  705.  
  706.     // Allocate an async command object for requesting a replug if the drive
  707.     // went away on us while we have volumes mounted.
  708.     
  709.     if (status == noErr)
  710.     {
  711.         status = FWAllocateFWCommandObject (&pFWSBP2DriverData->fwReplugID);
  712.     }
  713.     
  714.     if (status == noErr)
  715.     {
  716.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwReplugID,
  717.                                        pFWSBP2DriverData->fwDriverID,
  718.                                        0,
  719.                                        ReplugCompletionProc,
  720.                                        0);
  721.     }
  722.  
  723.     // Allocate an asynch command object to set the BUSY_TIMEOUT register after each login.
  724.     // This is kind of gross, but to do it right would be complicated and need some kind of
  725.     // state machine.
  726.     
  727.     if (status == noErr)
  728.     {
  729.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->busyTimeoutCommandID);
  730.     }
  731.     
  732.     if (status == noErr)
  733.     {
  734.         status = FWSetFWCommandParams (pFWSBP2DriverData->busyTimeoutCommandID,
  735.                                        pFWSBP2DriverData->fwDriverID,                // Device to write to
  736.                                        0,                                            // Flags (asynch)
  737.                                        BusyTimeoutCompletionProc,                    // Completion proc
  738.                                        0);                                            // Completion proc data
  739.     }
  740.  
  741.     if (status == noErr)
  742.     {
  743.         status = FWSetAsynchCommandParams (pFWSBP2DriverData->busyTimeoutCommandID,
  744.                                            0,                                        // Generation (unused)
  745.                                            0xffff,                                    // Address (high 16 bits)
  746.                                            0xf0000210,                                // Address (low 32 bits)
  747.                                            (Ptr) &pFWSBP2DriverData->busyTimeout,    // Payload (set later)
  748.                                            4,                                        // Payload size
  749.                                            4,                                        // Max payload
  750.                                            50,                                        // Retries
  751.                                            0);                                        // Flags (none)
  752.     }
  753.  
  754.     // Prepare a small well-aligned buffer for small requests
  755.     if (status == noErr)
  756.     {
  757.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  758.                                                     &pFWSBP2DriverData->smallBufferORB);
  759.         if (status == noErr)
  760.             status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->smallBufferORB, 12288);
  761.         
  762.         if (status == noErr)
  763.         {
  764.             // The documentation doesn't guarantee it, but this function always
  765.             // returns page-aligned memory.
  766.             
  767.             pFWSBP2DriverData->smallBuffer =
  768.                 MemAllocatePhysicallyContiguous (kSmallDoubleBufferSize, false);
  769.         
  770.             if (!pFWSBP2DriverData->smallBuffer)
  771.                 status = memFullErr;
  772.         }
  773.         
  774.         // FWSetSBP2NormalCommandBuffers copies all it's arguments and is synchronous
  775.         // so we can pass pointers from the stack for our buffer/length list.  By assigning
  776.         // the full buffer here, SBP-2 will be able to optimize when we use only part of
  777.         // the buffer, by avoiding the PrepareMemoryForIO.
  778.         
  779.         sizeTemp = kSmallDoubleBufferSize;
  780.         addrTemp.addressHi = 0;
  781.         addrTemp.addressLo = (UInt32) pFWSBP2DriverData->smallBuffer;
  782.         
  783.         if (status == noErr)
  784.             status = FWSetSBP2NormalCommandBuffers (pFWSBP2DriverData->smallBufferORB, 1, &addrTemp, &sizeTemp);
  785.  
  786.         if (status == noErr)
  787.             status = FWSetSBP2NormalCommandTimeout (pFWSBP2DriverData->smallBufferORB, durationMillisecond * 1000);
  788.     }
  789.     
  790.     // We are going to try to log in.  Make sure nobody ejects our interface.
  791.     if (status == noErr)
  792.     {    
  793.         status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
  794.         
  795.         deviceFlags |= kFWDeviceDoNotEjectCardBus;
  796.         
  797.         if (status == noErr)
  798.             status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
  799.     }
  800.     
  801.     // Save our driver data or clean up on error.
  802.     if (status == noErr)
  803.     {
  804.         
  805.         gpFWSBP2DriverData->drvrRefNum = refNum;
  806.         // And go ahead and login to the drive.
  807.         // !!!zzz realistically we need to make sure this drive
  808.         // belongs to us but for now we'll assume it does    
  809.         gpFWSBP2DriverData->pRegEntryID = *pRegEntryID;
  810.     
  811.         // BusManagementNotify didn't work...
  812.         FWSetFWClientResetNotifyProc(gpFWSBP2DriverData->fwDriverID, FWSBPResetNotify );
  813.         
  814.         pFWSBP2DriverData->loggedIn = false;
  815.         pFWSBP2DriverData->loginObjBusy = true;
  816.  
  817.         status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  818.             
  819.         while( gpFWSBP2DriverData->loginObjBusy )
  820.             ;
  821.     
  822.         if( !pFWSBP2DriverData->loggedIn ) {
  823.  
  824.             // We failed to log in.  We don't care if someone ejects our interface now.
  825.  
  826.             status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
  827.             
  828.             deviceFlags &= ~kFWDeviceDoNotEjectCardBus;
  829.             
  830.             if (status == noErr)
  831.                 status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
  832.     
  833.             return( openErr );
  834.         }
  835.     }
  836.     else
  837.     {//zzz should use terminate
  838.         if (pFWSBP2DriverData != nil)
  839.             PoolDeallocate ((Ptr) pFWSBP2DriverData);
  840.     }
  841.     
  842.     // If we got logged in, set the BUSY_TIMEOUT register so that the drive
  843.     // will retry if we busy a packet it sends us.
  844.     if (status == noErr)
  845.         status = SetBUSY_TIMEOUT ();
  846.         
  847.     // Try a few of these - helps you wake up in the morning. Sort of like a double latte.
  848.     
  849.     keepTrying = 25;
  850.     while( keepTrying-- && SBP2TUR(true) ) 
  851.         ;
  852.     
  853.     if( status == noErr )
  854.         status = SBP2CalculateMediaSize();
  855.  
  856.     HLock((Handle)GetDCtlEntry (refNum));
  857.     gpFWSBP2DriverData->dce = *(GetDCtlEntry (refNum));
  858.     
  859.     // Set up stuff before drive queue element.
  860.     if (status == noErr)
  861.     {
  862.         gpFWSBP2DriverData->driveStatus.diskInPlace = 1;
  863.         gpFWSBP2DriverData->driveStatus.installed = 1;
  864.         gpFWSBP2DriverData->driveStatus.qType = 1;
  865.     }
  866.  
  867.     // Compute drive size.
  868.     if (status == noErr)
  869.     {
  870.         gpFWSBP2DriverData->driveStatus.driveSize = gpFWSBP2DriverData->totalBlocks & 0xFFFF;
  871.         gpFWSBP2DriverData->driveStatus.driveS1 = (short)(gpFWSBP2DriverData->totalBlocks >> 16);
  872.     }
  873.  
  874.     // Find a drive number to use, starting with number 8.
  875.     if (status == noErr)
  876.     {
  877.         driveNum = 8;
  878.         pDrvQHdr = GetDrvQHdr ();
  879.         pDrvQEl = (DrvQElPtr) (pDrvQHdr->qHead);
  880.         while (pDrvQEl)
  881.         {
  882.             if ((pDrvQEl->dQDrive == driveNum) ||
  883.                 ((pDrvQEl->dQDrive + 1) == driveNum))//zzz hack to work around AddDrive bug.
  884.             {
  885.                 driveNum++;
  886.                 pDrvQEl = (DrvQElPtr) (pDrvQHdr->qHead);
  887.             }
  888.             else
  889.             {
  890.                 pDrvQEl = (DrvQElPtr) pDrvQEl->qLink;
  891.             }
  892.         }
  893.  
  894.         gpFWSBP2DriverData->driveStatus.dQDrive = driveNum;
  895.     }
  896.  
  897.     // Add the drive to the drive queue.
  898.     if (status == noErr)
  899.     {
  900.         gpFWSBP2DriverData->queuedDQEl = true;
  901.         AddDrive (refNum,
  902.                   gpFWSBP2DriverData->driveStatus.dQDrive,
  903.                   (DrvQEl *) &(gpFWSBP2DriverData->driveStatus.qLink));
  904.     }
  905.  
  906.     // Notify interested parties that a new drive has been added.
  907.     //zzz should we check error?
  908.     if (status == noErr)
  909.     {
  910.         PostEvent (diskEvt, (UInt32) gpFWSBP2DriverData->driveStatus.dQDrive);
  911.     }
  912.     return status;
  913. }
  914.  
  915.  
  916. ////////////////////////////////////////////////////////////////////////////////
  917. //
  918. // FWSBP2Terminate
  919. //
  920. //   This routine terminates the FireWire SBP2 sample driver.  It
  921. // deallocates a private data record and unregisters with the FireWire family.
  922. //
  923. // Note, currently this routine is never called.
  924. // Even if you unplug the device, nobody terminates the driver.
  925. //
  926.  
  927. static OSStatus    FWSBP2Terminate(void)
  928. {
  929.     OSStatus                    status = noErr;
  930.     UInt32                        orbNum;
  931.  
  932.     if (gpFWSBP2DriverData != nil)
  933.     {
  934.  
  935.         if (gpFWSBP2DriverData->loginCommandID)
  936.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  937.  
  938.         if (gpFWSBP2DriverData->loginCommandID)
  939.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->fwReconnectID);
  940.  
  941.         if( gpFWSBP2DriverData->queuedDQEl )
  942.             Dequeue( (QElemPtr)&gpFWSBP2DriverData->driveStatus.qLink, LMGetDrvQHdr() );
  943.  
  944.         //zzz We should check that ORB is not active before we deallocate it.
  945.         // We could issue a target reset to guarantee this.
  946.         
  947.         for( orbNum = 0; orbNum < kTotalORBs; orbNum++ ) {
  948.             if (gpFWSBP2DriverData->orbID[orbNum])
  949.                 FWDeallocateFWCommandObject (gpFWSBP2DriverData->orbID[orbNum]);
  950.         }
  951.  
  952.         if( gpFWSBP2DriverData->loggedIn )
  953.             SBP2Logout();
  954.         
  955.         if (gpFWSBP2DriverData->smallBuffer)
  956.             MemDeallocatePhysicallyContiguous (gpFWSBP2DriverData->smallBuffer);
  957.         
  958.         if (gpFWSBP2DriverData->smallBufferORB)
  959.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->smallBufferORB);
  960.             
  961.         if (gpFWSBP2DriverData->loginCommandID)
  962.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->loginCommandID);
  963.  
  964.         // Unregister with FireWire family.
  965.         if (gpFWSBP2DriverData->fwDriverID != kInvalidFWDriverID)
  966.             FWUnregisterDriver (gpFWSBP2DriverData->fwDriverID);
  967.  
  968.         // Deallocate our driver data.
  969.         PoolDeallocate ((Ptr) gpFWSBP2DriverData);
  970.         gpFWSBP2DriverData = nil;
  971.     }
  972.  
  973.     return status;
  974. }
  975.  
  976.  
  977.  
  978. ////////////////////////////////////////////////////////////////////////////////
  979. //
  980. // SBP2Logout
  981. //
  982. //   This routine performs a logout.
  983. //
  984.  
  985. static OSStatus    SBP2Logout( void )
  986. {
  987.     UInt32                        deviceFlags;
  988.     OSStatus                    status = noErr;
  989.  
  990.     gpFWSBP2DriverData->loginObjBusy = true;
  991.  
  992.     status = FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
  993.     
  994.     while( gpFWSBP2DriverData->loginObjBusy )
  995.         ;
  996.     
  997.     if (status == noErr)
  998.     {
  999.         gpFWSBP2DriverData->loggedIn = false;
  1000.         
  1001.         // We no longer care if anyone ejects our interface.
  1002.         status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
  1003.             
  1004.         deviceFlags &= ~kFWDeviceDoNotEjectCardBus;
  1005.             
  1006.         if (status == noErr)
  1007.             status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
  1008.     }
  1009.     
  1010.     return noErr;
  1011. }
  1012.  
  1013.  
  1014. static OSStatus FWSBP2Prime(
  1015.     AddressSpaceID                addressSpaceID,
  1016.     IOCommandID                    ioCommandID,
  1017.     IOCommandContents            ioCommandContents,
  1018.     IOCommandKind                ioCommandKind,
  1019.     Boolean                        isWrite)
  1020. {
  1021.     OSStatus                    status;
  1022.     UInt32                        startblk; 
  1023.     UInt32                        numblks;
  1024.     IOParamPtr                    ioPB;
  1025.     
  1026.     // save away some info about the current command (assume single threaded for now).
  1027.     gpFWSBP2DriverData->ioPB = ioPB = (IOParamPtr) ioCommandContents.pb;
  1028.     gpFWSBP2DriverData->ioCommandID = ioCommandID;
  1029.     gpFWSBP2DriverData->isWrite = isWrite;
  1030.  
  1031.     // calculate the starting block and block count (divide by 512) 
  1032.     
  1033.     if( ioPB->ioPosMode & 0x0100) {    // large volume format (>=4GB)
  1034.         startblk =    ( *(UInt32 *)((char*)&(ioPB->ioPosOffset)+2) << (16-9) ) +
  1035.                     ( *(UInt16 *)((char*)&(ioPB->ioPosOffset)+6) >> 9 );
  1036.     }
  1037.     else                                                // regular volume format (<4GB)
  1038.         startblk = (UInt32)(ioPB->ioPosOffset) >> 9;
  1039.  
  1040.     numblks = (UInt32)(ioPB->ioReqCount) >> 9;
  1041.  
  1042.     // Is count an integer number of blocks or block out of range of partition ? 
  1043.     if( ((ioPB->ioReqCount & (kBlockSize-1)) != 0)  ||
  1044.                (startblk+numblks > gpFWSBP2DriverData->totalBlocks))  
  1045.     {
  1046.         status = paramErr;
  1047.     } 
  1048.     else 
  1049.     {
  1050.         gpFWSBP2DriverData->retriesLeft = 30; // Totally arbitrary, probably overkill
  1051.         
  1052.         gpFWSBP2DriverData->ioPending = true;
  1053.         
  1054.         // Decide if we should use the small, fixed double buffer
  1055.         if (ioPB->ioReqCount <= kSmallDoubleBufferSize)
  1056.         {
  1057.             gpFWSBP2DriverData->useSmallBuffer = true;
  1058.             gpFWSBP2DriverData->immediate = (ioCommandKind == kImmediateIOCommandKind);            
  1059.             if (isWrite) BlockMoveData (ioPB->ioBuffer, gpFWSBP2DriverData->smallBuffer, ioPB->ioReqCount);
  1060.             
  1061.             // if this is a read we'll copy data out when we get good status
  1062.         }
  1063.         else
  1064.         {
  1065.             gpFWSBP2DriverData->useSmallBuffer = false;
  1066.         }
  1067.         
  1068.         // Can't hardly do nuthin if we aint logged in
  1069.         if( !gpFWSBP2DriverData->loggedIn ) {
  1070.         
  1071.             // For immediate command just bail with IOErr
  1072.             if( ioCommandKind == kImmediateIOCommandKind ) {
  1073.                 return( ioErr );
  1074.             }
  1075.             else if( gpFWSBP2DriverData->returnDiskErr ) {
  1076.                 // If user canceled our dialog return disk error to get clear any sync-wait
  1077.                 // loops and allow the machine to keep operating. For all we know the reason the
  1078.                 // drive went away was because the user spilled coffee on it and now they want
  1079.                 // to save their open files somewhere else.
  1080.                 IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1081.                 return( ioErr );
  1082.             }
  1083.             else {
  1084.                 // Dialog should still be on the screen, go away and wait for notification
  1085.                 // and retry the command then.
  1086.                 gpFWSBP2DriverData->count = numblks;
  1087.                 gpFWSBP2DriverData->sector = startblk;
  1088.                 gpFWSBP2DriverData->buffer = ioPB->ioBuffer;
  1089.                 return( ioInProgress );
  1090.             }
  1091.         }
  1092.  
  1093.         // Make call synchronously if we are an immediate call, else normal
  1094.         status = SBP2DoReadWriteBlocks( isWrite, numblks, startblk, ioPB->ioBuffer, ioCommandKind == kImmediateIOCommandKind );
  1095.         
  1096.     }
  1097.     if( status != ioInProgress ) {
  1098.         ioPB->ioActCount = 0;            /* report all or none */
  1099.         IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, status);
  1100.     }
  1101.     return(status);
  1102. }
  1103.  
  1104.  
  1105. ////////////////////////////////////////////////////////////////////////////////
  1106. //
  1107. // SBP2DoReadWriteBlocks
  1108. //
  1109. //   This routine reads block zero, assuming the target is a simple hard drive.
  1110. // 
  1111. //   The sync flag implies immediate. Don't ever call it with this flag true at
  1112. //   interrupt time. This will be used for device manager immediate calls and
  1113. //   probably partition map scanning code. Everything else should be asynchronous.
  1114. //
  1115.  
  1116. static OSStatus SBP2DoReadWriteBlocks(
  1117.     Boolean            isWrite,
  1118.     UInt32             count,
  1119.     UInt32             sector,
  1120.     Ptr             buffer,
  1121.     Boolean            immediate ) 
  1122. {
  1123.     FWCommandObjectID            orbID;
  1124.     OSStatus                    status = noErr;
  1125. #if VerifyWrites
  1126.     Boolean                        wasVerify;
  1127. #endif
  1128.     UInt8                        *command;
  1129.  
  1130.     // Remember some stuff for retries
  1131.     gpFWSBP2DriverData->count = count;
  1132.     gpFWSBP2DriverData->sector = sector;
  1133.     gpFWSBP2DriverData->buffer = buffer;
  1134.  
  1135.     // Double buffer if not aligned to drive's liking and not already using the small buffer
  1136.     if( ((long)buffer & 0x0000000F) && !gpFWSBP2DriverData->useSmallBuffer ) 
  1137.         gpFWSBP2DriverData->doubleBuffer = true;
  1138.     else
  1139.         gpFWSBP2DriverData->doubleBuffer = false;
  1140.     
  1141. #if VerifyWrites
  1142.     wasVerify = gpFWSBP2DriverData->needsVerify;
  1143.     if( isWrite ) 
  1144.         gpFWSBP2DriverData->needsVerify = true;
  1145. #endif
  1146.  
  1147.     gpFWSBP2DriverData->xferLeft = 0;            // assume no extra transfer
  1148.  
  1149.     if( count > kMaxTransfer ) {                // Transfer too big to do all at once?
  1150.         gpFWSBP2DriverData->xferLeft = count-kMaxTransfer;
  1151.         count = kMaxTransfer;
  1152.         gpFWSBP2DriverData->next_block = sector + count;    
  1153.  
  1154. #if VerifyWrites
  1155.         if( !wasVerify ) {
  1156. #endif
  1157.             gpFWSBP2DriverData->next_buffer = buffer + (count << 9);
  1158. #if VerifyWrites
  1159.         }
  1160. #endif
  1161.     } 
  1162.  
  1163.     if (gpFWSBP2DriverData->useSmallBuffer)
  1164.     {
  1165.         orbID = gpFWSBP2DriverData->smallBufferORB;
  1166.     }
  1167.     else
  1168.     {
  1169.         if( isWrite && gpFWSBP2DriverData->doubleBuffer )
  1170.             BlockMoveData (buffer, gpFWSBP2DriverData->dataBuffer, count << 9);
  1171.     
  1172.         if( immediate )
  1173.             orbID = gpFWSBP2DriverData->orbID[kImmedORB];
  1174.         else {
  1175.             orbID = gpFWSBP2DriverData->orbID[gpFWSBP2DriverData->currentORB];
  1176.             
  1177.             // Switch to the other ORB for next transaction
  1178.             gpFWSBP2DriverData->currentORB = ( gpFWSBP2DriverData->currentORB ? 0 : 1);
  1179.         }
  1180.     }
  1181.     
  1182.     // Prepare the ORB.
  1183.     // Page table total length must agree with ATAPI request length, or drive
  1184.     // will get confused.
  1185.         
  1186.     gpFWSBP2DriverData->buffers[0].addressHi = 0;
  1187.     gpFWSBP2DriverData->lengths[0] = (count << 9);
  1188.  
  1189.     if (gpFWSBP2DriverData->useSmallBuffer)
  1190.     {
  1191.         gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->smallBuffer;
  1192.         
  1193.         // This one won't call PrepareMemoryForIO because it's the same buffer we gave it before.
  1194.         status = FWSetSBP2NormalCommandBuffers (orbID, 1, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
  1195.     }
  1196.     else
  1197.     {    
  1198.         if( gpFWSBP2DriverData->doubleBuffer )
  1199.             gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->dataBuffer;
  1200.         else
  1201.             gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) buffer;
  1202.     
  1203.         status = FWSetSBP2NormalCommandBuffers (orbID, 1, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
  1204.     }
  1205.     
  1206.     // Form ATAPI command (SCSI-3, cribbed from MMC-2 spec)
  1207.     command = &gpFWSBP2DriverData->command[0];
  1208.  
  1209.     command[0] = (isWrite ? 0x2A : 0x28);            // Write or Read
  1210.     command[1] = 0;                                    // Mostly reserved
  1211.     command[2] = (sector >> 24) & 0xff;                // MSB of LBA
  1212.     command[3] = (sector >> 16) & 0xff;
  1213.     command[4] = (sector >> 8) & 0xff;
  1214.     command[5] = sector & 0xff;                        // LSB of LBA
  1215.     command[6] = 0;                                    // Reserved
  1216.     command[7] = (count >> 8) & 0xff;                // MSB of block count
  1217.     command[8] = count & 0xff;                        // LSB of block count
  1218.     command[9] = 0;                                    // Control (reserved)
  1219.     command[10] = 0;
  1220.     command[11] = 0x02;                                // Used DMA
  1221.  
  1222.     if (status == noErr)
  1223.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  1224.  
  1225.     if (status == noErr)
  1226.         status = FWSetSBP2NormalCommandFlags (orbID,
  1227.                                               (isWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
  1228.                                               kSBP2CommandCompleteNotify |
  1229.                                               kSBP2CommandImmediate |
  1230.                                               kSBP2CommandNormalORB);
  1231.  
  1232.     if( immediate ) {
  1233.         if (status == noErr)
  1234.             status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1235.     }
  1236.     else {
  1237.         if (status == noErr)
  1238.             status = FWSetFWCommandFlags (orbID, 0);
  1239.     }
  1240.     
  1241.     if (status == noErr)
  1242.         status = FWAppendSBP2Command (orbID);
  1243.     
  1244.     if( (status == noErr) && immediate )
  1245.     {
  1246.         // Wait for completion
  1247.         // Remember kiddies - don't do this at interrupt time!
  1248.         while( gpFWSBP2DriverData->immedStatus == ioInProgress )
  1249.             ;
  1250.         status = gpFWSBP2DriverData->immedStatus;
  1251.         
  1252.         // For immediate reads, now copy data out of our private buffer 
  1253.         if (!isWrite)
  1254.         {
  1255.             if (gpFWSBP2DriverData->useSmallBuffer)
  1256.             {
  1257.                 BlockMoveData (gpFWSBP2DriverData->smallBuffer, buffer, count << 9);
  1258.             }
  1259.             else
  1260.             {
  1261.                 if (gpFWSBP2DriverData->doubleBuffer)
  1262.                     BlockMoveData (gpFWSBP2DriverData->dataBuffer, buffer, count << 9);
  1263.             }
  1264.         }
  1265.     }
  1266.     
  1267.     if( (status == noErr) && !immediate ) {
  1268.         return( ioInProgress );
  1269.     }
  1270.     return status;
  1271. }
  1272.  
  1273.  
  1274. ////////////////////////////////////////////////////////////////////////////////
  1275. //
  1276. // SBPLoginNotify
  1277. //
  1278. //   This routine is called when a login command completes.
  1279. //
  1280.  
  1281. static OSStatus SBPLoginNotify(
  1282.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1283.     UInt32                        *pCommandAcceptance)
  1284. {
  1285.     
  1286.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginComplete)
  1287.     {
  1288.         gpFWSBP2DriverData->loggedIn = true;
  1289.         gpFWSBP2DriverData->returnDiskErr = false;
  1290.         
  1291.         // Set the BUSY_TIMEOUT register again.
  1292.         if (gpFWSBP2DriverData->busyTimeoutCommandBusy)
  1293.         {
  1294.             gpFWSBP2DriverData->busyTimeoutAgain = true;
  1295.             // Will set it again when the command finishes.
  1296.         }
  1297.         else
  1298.         {
  1299.             // Do this only if it's already been set (ie not first time)
  1300.             if (gpFWSBP2DriverData->busyTimeout)
  1301.                 if (FWWrite (gpFWSBP2DriverData->busyTimeoutCommandID) == noErr)
  1302.                     gpFWSBP2DriverData->busyTimeoutCommandBusy = true;
  1303.         }
  1304.         
  1305.         // If the user ejected the disk and then put it back we need to post a diskEvent to tell the File System
  1306.         if( gpFWSBP2DriverData->gotEject )
  1307.             PostEvent (diskEvt, (UInt32) gpFWSBP2DriverData->driveStatus.dQDrive);
  1308.  
  1309.         // Async login for reconnect? 
  1310.         if( gpFWSBP2DriverData->wasLoggedIn ) {
  1311.             
  1312.             if( gpFWSBP2DriverData->ioPending && gpFWSBP2DriverData->retriesLeft-- ) {
  1313.                 SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1314.             }
  1315.         }
  1316.         
  1317.         gpFWSBP2DriverData->wasLoggedIn = true;
  1318.         gpFWSBP2DriverData->gotEject = false; // volumes should be back.
  1319.         
  1320.         gpFWSBP2DriverData->fetchAgent.addressHi =
  1321.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 1);
  1322.         gpFWSBP2DriverData->fetchAgent.addressLo =
  1323.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 2);
  1324.         
  1325.     }
  1326.     
  1327.      if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2Reconnecting)
  1328.      {
  1329.         // Sit on any incoming requests until we are reconnected. They'll fail anyway.
  1330.         gpFWSBP2DriverData->loggedIn = false;
  1331.         gpFWSBP2DriverData->reconnecting = true;
  1332.  
  1333.      }
  1334.     else
  1335.         gpFWSBP2DriverData->reconnecting = false;
  1336.  
  1337.     
  1338.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectComplete)
  1339.      {
  1340.         gpFWSBP2DriverData->loggedIn = true;
  1341.         
  1342.         // Set the BUSY_TIMEOUT register again.
  1343.         if (gpFWSBP2DriverData->busyTimeoutCommandBusy)
  1344.         {
  1345.             gpFWSBP2DriverData->busyTimeoutAgain = true;
  1346.             // Will set it again when the command finishes.
  1347.         }
  1348.         else
  1349.         {
  1350.             // Do this only if it's already been set (ie not first time)
  1351.             if (gpFWSBP2DriverData->busyTimeout)
  1352.                 if (FWWrite (gpFWSBP2DriverData->busyTimeoutCommandID) == noErr)
  1353.                     gpFWSBP2DriverData->busyTimeoutCommandBusy = true;
  1354.         }
  1355.         
  1356.         // Restart pending IO if it exists.
  1357.         if( gpFWSBP2DriverData->ioPending ) {
  1358.             if( gpFWSBP2DriverData->retriesLeft-- ) {
  1359.                 SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1360.             }
  1361.             else {
  1362.                 gpFWSBP2DriverData->ioPending = false;
  1363.                 IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1364.             }
  1365.         }
  1366.     }
  1367.      
  1368.      if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginFailed) {
  1369.         
  1370.         // is this is the first login?
  1371.         if( gpFWSBP2DriverData->wasLoggedIn ) {
  1372.             // Hmmm. Did somebody else log into our drive while it was off the bus
  1373.             // or did something else prevent us from logging in? Perhaps the Mac Timed
  1374.             // out before the drive did and the drive rejected our login request because
  1375.             // it thought it had a valid login? For a single initiator environment the 
  1376.             // a good thing to do is probably try to login again until we succeed. Perhaps
  1377.             // even better would be to do this for the reconnect timeout + 1 second and
  1378.             // then start returning ioErr to the clients. I'll leave that as an exercise 
  1379.             // for the developers. This driver will just blindly keep trying to login.
  1380.             //
  1381.             // I changed this because after receiving wall-powered drives we noticed it
  1382.             // was possible to get a bizzare flashing dialog effect on a re-plug because
  1383.             // the Mac and the Drive were out of sync with regard to a valid login 
  1384.         
  1385.             gpFWSBP2DriverData->loggedIn = false;
  1386.             gpFWSBP2DriverData->wait4Replug = false;
  1387.             FWSBPLookForDrive();
  1388.         }
  1389.         else
  1390.             gpFWSBP2DriverData->loggedIn = false;
  1391.     }
  1392.     
  1393.      if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectFailed) {
  1394.         
  1395.         // if we didn't expect the drive to go away demand that the user put it back
  1396.         // Important - this function is always asynchronous to allow FSL to make forward
  1397.         // progress. We'll find out what happend (came back or user cancelled with Command-.)
  1398.         // in the completion routine.
  1399.         
  1400.         gpFWSBP2DriverData->loggedIn = false;
  1401.         
  1402.         if( !gpFWSBP2DriverData->gotEject ) {
  1403.             gpFWSBP2DriverData->wait4Replug = true;
  1404.             FWWaitForDeviceRePlug( gpFWSBP2DriverData->fwReplugID );
  1405.         }
  1406.     
  1407.     }
  1408.     
  1409.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1410.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1411. }
  1412.  
  1413.  
  1414. ////////////////////////////////////////////////////////////////////////////////
  1415. //
  1416. // SBPStatusNotify
  1417. //
  1418. //   This routine is called when an ORB generates status.
  1419. //   This routine is a complete mess. I hate SBP2 error reporting. How may ways are
  1420. //   there to tell you something went wrong?
  1421. //
  1422.  
  1423. static OSStatus SBPStatusNotify(
  1424.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1425.     UInt32                        *pCommandAcceptance)
  1426. {
  1427.     OSStatus                    compStatus;
  1428.     OSStatus                    status;
  1429.     OSStatus                    cmdStatus = ioErr;
  1430.     sbpStatusBlockPtr            sbpStatus;
  1431.     FWCommandObjectID            completedOrb;    // Which guy just finished
  1432.     Boolean                        statusValid = false;
  1433.     UInt32                        bufferLength;
  1434. #if VerifyWrites
  1435.     UInt32                        x;
  1436.     char                        debugStr[256];
  1437. #endif
  1438.     Boolean                        commandSuccessful = false;
  1439.  
  1440.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1441.     compStatus = FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1442.  
  1443.     if( ! (gpFWSBP2DriverData->loginObjBusy || gpFWSBP2DriverData->reconnecting) ) // Bogus timeout status?
  1444.     {                                                                               //Don't bother trying anything until we're connected to the device
  1445.         switch (pFWClientSBP2NotifyParams->notificationEvent)
  1446.         {
  1447.         
  1448.         case kSBP2NormalCommandStatus:
  1449.             if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length)) {
  1450.                 statusValid = true;
  1451.                 sbpStatus = (sbpStatusBlockPtr)pFWClientSBP2NotifyParams->message;
  1452.                 
  1453.                 // Always reset the FA if it reports dead status
  1454.                 if (sbpStatus->stSrcRespLen & 0x08) {
  1455.         
  1456.                     status = FWSetAsynchCommandParams
  1457.                         (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1458.                          0,                                                    // generation - ignored
  1459.                          gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1460.                          gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1461.                          (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1462.                          4,                                                    // quadlet write
  1463.                          0,                                                    // max payload - ignored
  1464.                          8,                                                    // max retries
  1465.                          0);                                                // no flags
  1466.                     
  1467.                     // Reset agent
  1468.                     if (status == noErr)
  1469.                     {
  1470.                         FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1471.                         return( noErr );    // Pick up thread from completionProc and retry command
  1472.                     }
  1473.                 }
  1474.                 else if( (sbpStatus->stSrcRespLen & 0x30) == 0 && sbpStatus->stSBPStatus == 0 ) {
  1475.                 
  1476.                     if( (sbpStatus->stSrcRespLen & 0x07) == 1 ) {
  1477.                         
  1478.                         cmdStatus = noErr;
  1479.                     }
  1480.                 }
  1481.             }
  1482.     
  1483.             // If no IO is in progress this was the Request Sense we did during initialization 
  1484.             // or some other IO not connected with an IO. Don't start retry state machine.
  1485.             if( !gpFWSBP2DriverData->ioPending )
  1486.                 break;
  1487.             
  1488.             // If this was a prime command then either call ioDone or start
  1489.             // the next chunk of the transfer
  1490.             if( statusValid && (gpFWSBP2DriverData->command[0] == 0x2a || gpFWSBP2DriverData->command[0] == 0x28)  ) {
  1491.                 
  1492.                 if( cmdStatus == noErr ) {
  1493.                 
  1494.                     if( gpFWSBP2DriverData->count > kMaxTransfer )
  1495.                         bufferLength = kMaxTransfer << 9;
  1496.                     else
  1497.                         bufferLength = gpFWSBP2DriverData->count << 9;
  1498.                     
  1499.                     // If read, small-buffer, and not sync, copy data out
  1500.                     // (immediate calls will copy out elsewhere - zzz I think it's redundant, clean it up)
  1501.                     if ((!gpFWSBP2DriverData->isWrite) &&
  1502.                         (gpFWSBP2DriverData->useSmallBuffer) &&
  1503.                         (!gpFWSBP2DriverData->immediate))
  1504.                     {
  1505.                         BlockMoveData (gpFWSBP2DriverData->smallBuffer, gpFWSBP2DriverData->buffer, bufferLength);
  1506.                     }
  1507.                     else
  1508.                     {
  1509.                         //zzz Does this happen twice for synchronous commands?
  1510.                         if( !gpFWSBP2DriverData->isWrite && gpFWSBP2DriverData->doubleBuffer ) {
  1511.                             BlockMoveData( gpFWSBP2DriverData->dataBuffer, gpFWSBP2DriverData->buffer, bufferLength);
  1512.                         }
  1513.                     }
  1514.     #if VerifyWrites
  1515.                     if( gpFWSBP2DriverData->needsVerify && gpFWSBP2DriverData->command[0] == 0x2a) {
  1516.                     
  1517.                         // Read data for comparison
  1518.                         gpFWSBP2DriverData->whatWasWritten = (UInt8 *)gpFWSBP2DriverData->buffer;
  1519.                         SBP2DoReadWriteBlocks( false, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, (char *)gpFWSBP2DriverData->verifyBuffer, false);                
  1520.                         break;
  1521.                     }
  1522.                     
  1523.                     if( gpFWSBP2DriverData->needsVerify && gpFWSBP2DriverData->command[0] != 0x2a ) {
  1524.     
  1525.                         // Do the comparison
  1526.                         for( x = 0; x < bufferLength; x++ ) { 
  1527.                         
  1528.                             if( gpFWSBP2DriverData->whatWasWritten[x] != gpFWSBP2DriverData->verifyBuffer[x] ) {
  1529.                                 sprintf (debugStr, "pFWSBP2DiskDriver: Data mismatch! Written: %lx, Read: %lx, Offset %lx",
  1530.                                             (long) gpFWSBP2DriverData->whatWasWritten,
  1531.                                             (long) gpFWSBP2DriverData->verifyBuffer,
  1532.                                             (long) x);
  1533.                                 DebugStr ((ConstStr255Param) c2pstr (debugStr));
  1534.                                 break;
  1535.                             }
  1536.                         }
  1537.                         gpFWSBP2DriverData->needsVerify = false;
  1538.                     }
  1539.     #endif
  1540.     
  1541.                     if( gpFWSBP2DriverData->xferLeft ) {
  1542.                         SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->xferLeft, gpFWSBP2DriverData->next_block, gpFWSBP2DriverData->next_buffer, false);
  1543.                         break;
  1544.                     }
  1545.                     
  1546.                     gpFWSBP2DriverData->dce->dCtlPosition += (gpFWSBP2DriverData->ioPB->ioActCount = gpFWSBP2DriverData->ioPB->ioReqCount);
  1547.                     gpFWSBP2DriverData->ioPending = false;
  1548.                     IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, noErr);
  1549.                     break;
  1550.                 }
  1551.             }
  1552.             
  1553.             // If we got this far something bad happened so we should retry the current command
  1554.             if( gpFWSBP2DriverData->retriesLeft-- ) {
  1555.                 SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1556.             }
  1557.             else {
  1558.                 gpFWSBP2DriverData->ioPending = false;
  1559.                 IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1560.             }
  1561.             break;
  1562.             
  1563.         case kSBP2NormalCommandReset:
  1564.             // Not much to do here. We'll retry when we get reconnectComplete notification.
  1565.             break;
  1566.     
  1567.         case kSBP2NormalCommandTimeout:
  1568.             // Fetch agent never sent us status. 
  1569.             
  1570.     #if needLUNReset
  1571.             // Some SBP 2 devices have trouble recovering from error conditions. Preferably we would
  1572.             // reset the FA but some devices need to be kicked harder than others.
  1573.     
  1574.             if (gpFWSBP2DriverData->lunResetBusy)
  1575.             {
  1576.                 gpFWSBP2DriverData->lunResetAgain = true;
  1577.             }
  1578.             else
  1579.             {
  1580.                 gpFWSBP2DriverData->lunResetBusy = true;
  1581.                 FWSBP2Manage( gpFWSBP2DriverData->fwLUNReset_ID);
  1582.             }
  1583.             return(noErr);
  1584.     #else
  1585.             // Fetch agent never sent us status. Try resetting it. We'll retry from the completionProc
  1586.             status = FWSetAsynchCommandParams
  1587.                 (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1588.                  0,                                                    // generation - ignored
  1589.                  gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1590.                  gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1591.                  (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1592.                  4,                                                    // quadlet write
  1593.                  0,                                                    // max payload - ignored
  1594.                  8,                                                    // max retries
  1595.                  0);                                                // no flags
  1596.             
  1597.             // Reset agent
  1598.             if (status == noErr)
  1599.             {
  1600.                 FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1601.                 return(noErr);
  1602.             }
  1603.     #endif
  1604.             break;
  1605.             
  1606.         case kSBP2UnsolicitedStatus:
  1607.         default:
  1608.             //DebugStr("\pUnsolicited status of some sort");
  1609.             break;
  1610.         }
  1611.     }
  1612.  
  1613.     completedOrb = pFWClientSBP2NotifyParams->fwCommandObjectID;
  1614.  
  1615.     if( completedOrb == gpFWSBP2DriverData->orbID[kImmedORB] ) {
  1616.         gpFWSBP2DriverData->immedStatus = cmdStatus;
  1617.     }
  1618.  
  1619.     return( compStatus );
  1620.  
  1621. }
  1622.  
  1623.  
  1624. ////////////////////////////////////////////////////////////////////////////////
  1625. //
  1626. // SBPUnsolicitedStatusNotify
  1627. //
  1628. //   This routine is called when an unsolicited status is received.
  1629. //
  1630.  
  1631. static OSStatus SBPUnsolicitedStatusNotify(
  1632.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1633.     UInt32                        *pCommandAcceptance)
  1634. {
  1635.     // Should now reset the Unsolocited Status Enabler - or else we'll never get any more.
  1636.     // This driver just receives one to prove that it can be done.
  1637.  
  1638.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1639.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1640. }
  1641.  
  1642.  
  1643. ////////////////////////////////////////////////////////////////////////////////
  1644. //
  1645. // SBP2Control
  1646. //
  1647. //   Mass storage control routine.
  1648. //
  1649.  
  1650. static OSStatus SBP2Control(
  1651.     AddressSpaceID                addressSpaceID,
  1652.     IOCommandID                    ioCommandID,
  1653.     IOCommandContents            ioCommandContents,
  1654.     IOCommandKind                ioCommandKind)
  1655. {
  1656.     OSStatus                    status = noErr;
  1657.  
  1658.     switch (((CntrlParam *) ioCommandContents.pb)->csCode)
  1659.     {
  1660.         case 5 :        // verifyTheDisc
  1661.             break;
  1662.  
  1663.         case 6 :        // formatTheDisc
  1664.             break;
  1665.  
  1666.         case 21 :        // getDriveIcon [HD]
  1667.         case 22 :        // getMediaIcon [HD]
  1668.             *((UInt32 *) &(((CntrlParam *) ioCommandContents.pb)->csParam[0])) =
  1669.                 (UInt32) (staticIconData);
  1670.             break;
  1671.  
  1672.         case 7 :        // ejectTheDisc
  1673.             status = noErr;
  1674.             gpFWSBP2DriverData->gotEject = true;
  1675.             // Spin down the drive...
  1676.             SBP2Logout();
  1677.             break;
  1678.         case 23 :        // driveInfo [HD]
  1679.         case 70 :        // setPowerMode [HD]
  1680.                         // Friendly drivers spin their disks down here.
  1681.         default :
  1682.             status = controlErr;
  1683.             break;
  1684.     }
  1685.  
  1686.     // We're complete.
  1687.     if (ioCommandKind == kImmediateIOCommandKind)
  1688.         return (status);
  1689.     else 
  1690.         return (IOCommandIsComplete (ioCommandID, status));
  1691. }
  1692.  
  1693.  
  1694. ////////////////////////////////////////////////////////////////////////////////
  1695. //
  1696. // SBP2Status
  1697. //
  1698. //   Mass storage status routine.
  1699. //
  1700.  
  1701. static OSStatus SBP2Status(
  1702.     AddressSpaceID                addressSpaceID,
  1703.     IOCommandID                    ioCommandID,
  1704.     IOCommandContents            ioCommandContents,
  1705.     IOCommandKind                ioCommandKind)
  1706. {
  1707.     OSStatus                    status = noErr;
  1708.     DriverGestaltParam            * gestaltPtr;
  1709.  
  1710.     switch (((CntrlParam *) ioCommandContents.pb)->csCode)
  1711.     {
  1712.         case kDriverGestaltCode:                    
  1713.             gestaltPtr = (DriverGestaltParam*)ioCommandContents.pb;
  1714.             switch(gestaltPtr->driverGestaltSelector) 
  1715.             {
  1716.                 case kdgSync:
  1717.                     GetDriverGestaltSyncResponse(gestaltPtr)->behavesSynchronously = false;
  1718.                     break;
  1719.                 
  1720.                 case kdgDeviceType:
  1721.                     GetDriverGestaltDevTResponse(gestaltPtr)->deviceType = kdgDiskType;    
  1722.                     break;
  1723.                 
  1724.                 case kdgInterface:
  1725.                     GetDriverGestaltIntfResponse(gestaltPtr)->interfaceType = kdgFireWireIntf;
  1726.                     break;
  1727.                 
  1728.                 case kdgVersion:
  1729.                     *GetDriverGestaltVersionResponse(gestaltPtr) = gFWDiskVersion;
  1730.                     break;
  1731.                 
  1732.                 case kdgBoot:
  1733.                     // Need to figure out what to do with this. !!! Vers 3.0
  1734.                     break;
  1735.                     
  1736.                 case kdgVMOptions:
  1737.                     // Don't let VM use this disk for a backing store.
  1738.                     GetDriverGestaltVMOptionsResponse(gestaltPtr)->vmOptions = kAllowVMNoneMask;
  1739.                     break;
  1740.                 
  1741.                 case kdgFlush:
  1742.                     // May be important if your device has a write cache!
  1743.                     GetDriverGestaltFlushResponse(gestaltPtr)->canFlush = false;
  1744.                     GetDriverGestaltFlushResponse(gestaltPtr)->needsFlush = false;
  1745.                     break;
  1746.  
  1747.                 default:
  1748.                     status = statusErr;
  1749.                     break;
  1750.             }
  1751.             break;
  1752.         case kDriveStatus:    // Do we care? Maybe for locked volumes
  1753.             BlockMove(&gpFWSBP2DriverData->driveStatus,&((CntrlParam *) ioCommandContents.pb)->csParam[0], sizeof(DrvSts));
  1754.             break;
  1755.         default :
  1756.             status = statusErr;
  1757.             break;
  1758.     }
  1759.  
  1760.     // We're complete.
  1761.     if (ioCommandKind == kImmediateIOCommandKind)
  1762.         return (status);
  1763.     else
  1764.         return (IOCommandIsComplete (ioCommandID, status));
  1765. }
  1766.  
  1767. ////////////////////////////////////////////////////////////////////////////////
  1768. //
  1769. // SBP2CalculateMediaSize
  1770. //
  1771. //   This routine performs a mode sense to calculate the media size
  1772. // This routine makes only synchronous calls, so it must be called only at task
  1773. // level.
  1774. //
  1775.  
  1776. static OSStatus SBP2CalculateMediaSize( void )
  1777. {
  1778.     FWCommandObjectID            orbID;
  1779.     FWAddress                    buffers[1];
  1780.     UInt32                        lengths[1];
  1781.     char                        buffer[256];
  1782. #define usesModeSense10 0
  1783. #if usesModeSense10
  1784.     UInt8                        command[12] = {0x5a, 0x08, 0x3e, 0, 0, 0, 0, 0, 0xff, 0, 0, 0};
  1785. #else
  1786.     UInt8                        command[12] = {0x25, 0, 0x00, 0, 0x00, 0, 0, 0, 0, 0, 0, 0};
  1787.     //UInt8                        command[12] = {0x1a, 0, 0x3e, 0, 0x7f, 0, 0, 0, 0, 0, 0, 0};
  1788. #endif
  1789.     OSStatus                    status;
  1790.  
  1791.     // !!! Comment this out if your drive supports Read Capacity    
  1792.     //gpFWSBP2DriverData->totalBlocks = 0x200000;
  1793.     //return noErr;
  1794.     
  1795.     orbID = gpFWSBP2DriverData->orbID[kImmedORB];    // Immediate ORB
  1796.     
  1797.     // Prepare the ORB.
  1798.     
  1799.     buffers[0].addressHi = 0;
  1800.     buffers[0].addressLo = (UInt32) buffer;
  1801.     lengths[0] = 0x08;
  1802.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  1803.  
  1804.     if (status == noErr)
  1805.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  1806.     
  1807.     if (status == noErr)
  1808.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  1809.     
  1810.     if (status == noErr)
  1811.         status = FWSetSBP2NormalCommandFlags (orbID,
  1812.                                               kSBP2CommandTransferDataFromTarget |
  1813.                                               kSBP2CommandCompleteNotify |
  1814.                                               kSBP2CommandImmediate |
  1815.                                               kSBP2CommandNormalORB);
  1816.     
  1817.     if (status == noErr)
  1818.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1819.         
  1820.      *(long*)&buffer[0] = 0;
  1821.     
  1822.     gpFWSBP2DriverData->immedStatus = ioInProgress; // Remember we're busy with this guy
  1823.     
  1824.     if (status == noErr)
  1825.         status = FWAppendSBP2Command (orbID);
  1826.     
  1827.     // The Append command was synchronous.  When it returns, the command has been
  1828.     // appended to the target.  But the target probably has not executed the command yet.
  1829.     
  1830.     if (status == noErr)
  1831.     {
  1832.         // Remember kiddies - don't do this at interrupt time!
  1833.         while( gpFWSBP2DriverData->immedStatus == ioInProgress )
  1834.             ;
  1835.         
  1836.         // Really need to try and reset the drive here but I'm not feeling up to it at the moment.
  1837.         // Perhaps a LogicalUnitReset might be in order...
  1838.         
  1839.         if( *(long*)&buffer[0] == 0 )
  1840.             return( ioErr );
  1841.             
  1842.         gpFWSBP2DriverData->totalBlocks = *(long*)&buffer[0] - 1;
  1843.     }
  1844.     else 
  1845.         return( ioErr );
  1846.     
  1847.     return noErr;
  1848. }
  1849.  
  1850.  
  1851. ////////////////////////////////////////////////////////////////////////////////
  1852. //
  1853. // SBP2TUR
  1854. //
  1855. //   Some drives need this 
  1856. //
  1857.  
  1858. static OSStatus SBP2TUR( Boolean immediate )
  1859. {
  1860.     FWCommandObjectID            orbID;
  1861.     UInt8                        * command;
  1862.     OSStatus                    status;
  1863.  
  1864.         
  1865.     if( immediate )
  1866.         orbID = orbID = gpFWSBP2DriverData->orbID[kImmedORB];
  1867.     else {
  1868.         orbID = gpFWSBP2DriverData->orbID[gpFWSBP2DriverData->currentORB];
  1869.         
  1870.         // Switch to the other ORB for next transaction
  1871.         gpFWSBP2DriverData->currentORB = ( gpFWSBP2DriverData->currentORB ? 0 : 1);
  1872.     }
  1873.     
  1874.     command = &gpFWSBP2DriverData->command[0];
  1875.     
  1876.     command[0] = 0x00;                                // TUR
  1877.     command[1] = 0;    
  1878.     command[2] = 0;    
  1879.     command[3] = 0;
  1880.     command[4] = 0;
  1881.     command[5] = 0;
  1882.     command[6] = 0;
  1883.     command[7] = 0;
  1884.     command[8] = 0;
  1885.     command[9] = 0;
  1886.     command[10] = 0;
  1887.     command[11] = 0;
  1888.  
  1889.     // Prepare the ORB.
  1890.     
  1891.     gpFWSBP2DriverData->buffers[0].addressHi = 0;
  1892.     gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->aBuffer;
  1893.     gpFWSBP2DriverData->lengths[0] = 0;
  1894.     FWSetSBP2NormalCommandBuffers (orbID, 0, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
  1895.     
  1896.     status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  1897.     
  1898.     if (status == noErr)
  1899.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 5000);
  1900.     
  1901.     if (status == noErr)
  1902.         status = FWSetSBP2NormalCommandFlags (orbID,
  1903.                                               kSBP2CommandCompleteNotify |
  1904.                                               kSBP2CommandImmediate |
  1905.                                               kSBP2CommandNormalORB);
  1906.             
  1907.     if( immediate ) {
  1908.         if (status == noErr)
  1909.             status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1910.     }
  1911.     else {
  1912.         if (status == noErr)
  1913.             status = FWSetFWCommandFlags (orbID, 0);
  1914.     }
  1915.     
  1916.     gpFWSBP2DriverData->immedStatus = ioInProgress; // Remember we're busy with this guy
  1917.  
  1918.     if (status == noErr) {
  1919.         status = FWAppendSBP2Command (orbID);
  1920.         //if( status )
  1921.         //    DebugStr("\pFailed Append");
  1922.     }
  1923.     
  1924.     // The Append command was synchronous.  When it returns, the command has been
  1925.     // appended to the target.  But the target probably has not executed the command yet.
  1926.     
  1927.     if( (status == noErr) && immediate )
  1928.     {
  1929.         // Wait for completion
  1930.         // Remember kiddies - don't do this at interrupt time!
  1931.         while( gpFWSBP2DriverData->immedStatus == ioInProgress )
  1932.             ;
  1933.         status = gpFWSBP2DriverData->immedStatus;
  1934.     }
  1935.     
  1936.     if( (status == noErr) && !immediate ) {
  1937.         return( ioInProgress );
  1938.     }
  1939.         
  1940.     return status;
  1941. }
  1942.  
  1943.  
  1944. ////////////////////////////////////////////////////////////////////////////////
  1945. //
  1946. // ResetFACompletionProc
  1947. //
  1948. void
  1949. ResetFACompletionProc(
  1950.     FWCommandObjectID            fwCommandObjectID,
  1951.     OSStatus                    commandStatus,
  1952.     UInt32                        completionProcData)
  1953. {
  1954.     // Had to reset the fetch agent. If doing an IO the restart it. Otherwise report
  1955.     // and error (was an immediate or utility command).
  1956.     if( gpFWSBP2DriverData->ioPending ) {
  1957.         if( gpFWSBP2DriverData->retriesLeft-- ) {
  1958.             SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1959.         }
  1960.         else {
  1961.             gpFWSBP2DriverData->ioPending = false;
  1962.             IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1963.         }
  1964.     }
  1965.     else {
  1966.         gpFWSBP2DriverData->immedStatus = -1;    // If we had to reset the fetch agent we got an error...
  1967.     }
  1968. }
  1969.  
  1970.  
  1971. ////////////////////////////////////////////////////////////////////////////////
  1972. //
  1973. // BusyTimeoutCompletionProc
  1974. //
  1975. void
  1976. BusyTimeoutCompletionProc(
  1977.     FWCommandObjectID            fwCommandObjectID,
  1978.     OSStatus                    commandStatus,
  1979.     UInt32                        completionProcData)
  1980. {
  1981.     gpFWSBP2DriverData->busyTimeoutCommandBusy = false;
  1982.     
  1983.     // We may have logged in again but weren't able to call this command
  1984.     // because it was still busy.  If so, start it up again.
  1985.  
  1986.     if (gpFWSBP2DriverData->busyTimeoutAgain)
  1987.     {
  1988.         gpFWSBP2DriverData->busyTimeoutAgain = false;
  1989.  
  1990.         if (FWWrite (gpFWSBP2DriverData->busyTimeoutCommandID) == noErr)
  1991.             gpFWSBP2DriverData->busyTimeoutCommandBusy = true;
  1992.     }
  1993. }
  1994.  
  1995.  
  1996. ////////////////////////////////////////////////////////////////////////////////
  1997. //
  1998. // LoginCompletionProc
  1999. //
  2000. void
  2001. LoginCompletionProc(
  2002.     FWCommandObjectID            fwCommandObjectID,
  2003.     OSStatus                    commandStatus,
  2004.     UInt32                        completionProcData)
  2005. {
  2006.     gpFWSBP2DriverData->loginObjBusy = false;
  2007.     
  2008.     // If this is an attempt to clear an error condition - try logging in again
  2009.     if( gpFWSBP2DriverData->reLogin ) {
  2010.         gpFWSBP2DriverData->reLogin = false;
  2011.         FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  2012.     }
  2013. }
  2014.  
  2015.  
  2016. ////////////////////////////////////////////////////////////////////////////////
  2017. //
  2018. // ManageCompletionProc
  2019. //
  2020. void
  2021. ManageCompletionProc(
  2022.     FWCommandObjectID            fwCommandObjectID,
  2023.     OSStatus                    commandStatus,
  2024.     UInt32                        completionProcData)
  2025. {
  2026.     OSStatus                    status;
  2027.  
  2028.     if (gpFWSBP2DriverData->lunResetAgain)
  2029.     {
  2030.         gpFWSBP2DriverData->lunResetAgain = false;
  2031.         FWSBP2Manage (gpFWSBP2DriverData->fwLUNReset_ID);
  2032.     }
  2033.     else
  2034.     {
  2035.         gpFWSBP2DriverData->lunResetBusy = false;
  2036.         
  2037.         status = FWSetAsynchCommandParams
  2038.             (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  2039.              0,                                                    // generation - ignored
  2040.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  2041.              gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  2042.              (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  2043.              4,                                                    // quadlet write
  2044.              0,                                                    // max payload - ignored
  2045.              8,                                                    // max retries
  2046.              0);                                                // no flags
  2047.         
  2048.         // Reset agent
  2049.         if (status == noErr)
  2050.         {
  2051.             FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  2052.         }
  2053.     }
  2054. }
  2055.  
  2056.  
  2057. ////////////////////////////////////////////////////////////////////////////////
  2058. //
  2059. // ReconnectReadCompletionProc
  2060. //
  2061. void
  2062. ReconnectReadCompletionProc(
  2063.     FWCommandObjectID            fwCommandObjectID,
  2064.     OSStatus                    commandStatus,
  2065.     UInt32                        completionProcData)
  2066. {
  2067.     UInt32                        deviceFlags;
  2068.     OSStatus                     status;
  2069.  
  2070.     if( !commandStatus ) {
  2071.         // This seems to happen if we get replugged after being unmounted, so we
  2072.         // need to set the CardBus eject prevention bit again.
  2073.         
  2074.         status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
  2075.         
  2076.         deviceFlags |= kFWDeviceDoNotEjectCardBus;
  2077.         
  2078.         if (status == noErr)
  2079.             status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
  2080.  
  2081.         // Login again
  2082.         if (status == noErr)
  2083.             status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  2084.     }
  2085.     else
  2086.         gpFWSBP2DriverData->loginObjBusy = false;
  2087.  
  2088. }
  2089.  
  2090. ////////////////////////////////////////////////////////////////////////////////
  2091. //
  2092. // ReplugCompletionProc
  2093. //
  2094. void
  2095. ReplugCompletionProc(
  2096.     FWCommandObjectID            fwCommandObjectID,
  2097.     OSStatus                    commandStatus,
  2098.     UInt32                        completionProcData)
  2099. {
  2100.     gpFWSBP2DriverData->wait4Replug = false;
  2101.     if( !commandStatus ) {
  2102.         // We could just log back into the drive again here but I've found its better to rely
  2103.         // on the look for the device after reset notification which will keep functioning even
  2104.         // after the user does a Command-. This way if the user realizes they made a mistake and
  2105.         // plug the drive back in we'll see it and login correctly.
  2106.         gpFWSBP2DriverData->returnDiskErr = false;
  2107.         
  2108.         // Go look for the drive and login if necessary.
  2109.         // Note that this guy is protected by a semaphore so that we won't try to use
  2110.         // either fwReplugID or loginCommandID more than once.
  2111.         FWSBPLookForDrive();
  2112.     }
  2113.     else {
  2114.         // return ioErr for our pending command and all subsequent commands
  2115.         if( gpFWSBP2DriverData->ioPending ) 
  2116.             IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  2117.         gpFWSBP2DriverData->returnDiskErr = true;
  2118.         
  2119.     }
  2120.  
  2121. }
  2122.  
  2123.  
  2124. ////////////////////////////////////////////////////////////////////////////////
  2125. //
  2126. // FWSBPLookForDrive
  2127. //
  2128. // Starts a Read, Login, Retry thread for our drive. Used after a reset or if
  2129. // we somehow got ORB status while not logged in.
  2130. //
  2131. static void FWSBPLookForDrive( void )
  2132. {
  2133.     OSStatus                    status = noErr;
  2134.  
  2135.     if( gpFWSBP2DriverData->wait4Replug )    
  2136.         return;    // Waiting for FSL to tell us what to do
  2137.  
  2138.     if( !gpFWSBP2DriverData->loggedIn && ! gpFWSBP2DriverData->reconnecting ) {
  2139.         
  2140.         if( CompareAndSwap( false, true, (unsigned long *) &gpFWSBP2DriverData->loginObjBusy ) ) {
  2141.     
  2142.             // We've been disconnected from our device and we need to know
  2143.             // whether it came back (as a result of this reset or re-plug notification.
  2144.             // Seems like the easiest way is to try a read from the device's CSR ROM.
  2145.             // If it works we can try to login and resume any command we had pending.
  2146.         
  2147.             status = FWSetAsynchCommandParams
  2148.                         (gpFWSBP2DriverData->fwReconnectID,
  2149.                          0,
  2150.                          0xffff,
  2151.                          0xf0000400,    
  2152.                          (Ptr) &gpFWSBP2DriverData->bitBucket,                        // Actual data doesn't matter
  2153.                          4,                                                            // length of params
  2154.                          4,                                                            // max payload
  2155.                          4,                                                            // max retries
  2156.                          0);                                                        // 
  2157.                          
  2158.             if (status == noErr)
  2159.             {
  2160.                 status = FWRead (gpFWSBP2DriverData->fwReconnectID);
  2161.                 
  2162.             }
  2163.             
  2164.             if( status ) {
  2165.                 gpFWSBP2DriverData->loginObjBusy = false;
  2166.             }
  2167.  
  2168.         }
  2169.     }
  2170. }
  2171.  
  2172. ////////////////////////////////////////////////////////////////////////////////
  2173. //
  2174. // FWSBPResetNotify
  2175. //
  2176.  
  2177. static OSStatus    FWSBPResetNotify(
  2178.     FWClientInterfaceParamsPtr    pFWClientInterfaceParams,
  2179.     UInt32                        *pCommandAcceptance)
  2180. {
  2181.  
  2182.     FWSBPLookForDrive();
  2183.  
  2184.     // Complete FireWire client command.
  2185.     FWClientCommandIsComplete (pFWClientInterfaceParams->fwClientCommandID, noErr);
  2186.  
  2187.     // Return command acceptance.
  2188.     //zzz is this the right way?  If we've completed the command, we can accept more.
  2189.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  2190.  
  2191.     return noErr;
  2192. }
  2193.  
  2194.  
  2195. ///////////////////////////////////////////////
  2196. //
  2197. // Set the BUSY_TIMEOUT register in the drive.
  2198. // This all runs at task level during the install.
  2199. //
  2200.  
  2201. static OSStatus SetBUSY_TIMEOUT (void)
  2202. {
  2203.     FWCommandObjectID            commandID;
  2204.     UInt32                        busyTimeout;
  2205.     OSStatus                    allocStatus;
  2206.     OSStatus                    status = noErr;
  2207.     
  2208.     // Prepare a command object to quadlet read/write the BUSY_TIMEOUT register at 0x210.
  2209.     
  2210.     allocStatus = status = FWAllocateAsynchCommandObject (&commandID);
  2211.     
  2212.     if (status == noErr)
  2213.         status = FWSetFWCommandParams (commandID,
  2214.                                        gpFWSBP2DriverData->fwDriverID,
  2215.                                        kFWCommandSyncFlag, 0, 0);
  2216.  
  2217.     if (status == noErr)
  2218.         status = FWSetAsynchCommandParams
  2219.                     (commandID, 0, 0xffff, 0xf0000210, (Ptr) &busyTimeout, 4, 4, 8, 0);
  2220.     
  2221.     // Read old value, set our desired retry count, and write it back.
  2222.     
  2223.     if (status == noErr)
  2224.         status = FWRead (commandID);
  2225.  
  2226.     if (status == noErr)
  2227.     {
  2228.         busyTimeout &= 0xfffffff0;        // Preserve other bits
  2229.         busyTimeout |= 0x0000000f;        // Set retry count to 15
  2230.         
  2231.         gpFWSBP2DriverData->busyTimeout = busyTimeout;
  2232.         
  2233.         status = FWWrite (commandID);
  2234.     }
  2235.     
  2236.     if (allocStatus == noErr)
  2237.         FWDeallocateFWCommandObject (commandID);
  2238.         
  2239.     return status;
  2240. }
  2241.  
  2242.  
  2243.  
  2244.